{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# DemoStrategy"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 视频中介绍了针对四只股票的等权重投资策略，本段代码展示了利用quantOS系统进行策略回测及仿真交易的具体步骤。\n",
    "## 在程序运行之前，需要您在环境设置中更改以下参数：\n",
    "## 1. 将YourPhoneNo.改为您在quantOS网站注册的手机号;\n",
    "## 2. 将YourToken改为您的token;\n",
    "## 3. 将YourStrategyNo.改为您的策略号。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. 环境设置"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# -*- encoding: utf-8 -*-\n",
    "import time\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "\n",
    "from jaqs.data import RemoteDataService\n",
    "from jaqs.trade import AlphaBacktestInstance\n",
    "from jaqs.trade import PortfolioManager\n",
    "#from jaqs.trade import RealTimeTradeApi\n",
    "\n",
    "import jaqs.util as jutil\n",
    "import jaqs.trade.analyze as ana\n",
    "from jaqs.trade import AlphaStrategy\n",
    "from jaqs.trade import AlphaTradeApi\n",
    "from jaqs.trade import model\n",
    "from jaqs.data import DataView"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 设置文件存储路径\n",
    "dataview_dir_path = 'demoStrategy/dataview'\n",
    "backtest_result_dir_path = 'demoStrategy'\n",
    "\n",
    "# 设置服务器地址、用户名密码\n",
    "# 例如：\n",
    "# data_config = {\n",
    "#   \"remote.data.address\": \"tcp://data.tushare.org:8910\",\n",
    "#   \"remote.data.username\":  '18688888888',\n",
    "#   \"remote.data.password\":  '23sdjfk209d0fs9dejkl2j3k4j9d0fsdf'}\n",
    "\n",
    "phone = \"xxxx\"\n",
    "token = \"xxxxxxxxxx\"\n",
    "\n",
    "data_config = {\n",
    "  \"remote.data.address\": \"tcp://data.tushare.org:8910\",\n",
    "  \"remote.data.username\":  phone,\n",
    "  \"remote.data.password\":  token}\n",
    "trade_config = {\n",
    "  \"remote.trade.address\": \"tcp://gw.quantos.org:8901\",\n",
    "  \"remote.trade.username\":  phone,\n",
    "  \"remote.trade.password\":  token}\n",
    "\n",
    "\n",
    "# 设置Strategy number\n",
    "# 例如：StrategyNo = 1043\n",
    "StrategyNo = 'YourStrategyNo.'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. 参数设置"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# -------------------------------------------------------------------------------\n",
    "# 设置目标股票、业绩基准、权重、时间\n",
    "# -------------------------------------------------------------------------------\n",
    "symbol_weights = {'600519.SH': 0.25,\n",
    "                  '600036.SH': 0.25,\n",
    "                  '601318.SH': 0.25,\n",
    "                  '000651.SZ': 0.25}\n",
    "\n",
    "benchmark = '000300.SH'\n",
    "\n",
    "my_symbols = ','.join(symbol_weights.keys())\n",
    "start_date = 20170201\n",
    "end_date = 20171001\n",
    "\n",
    "# 定义权重函数\n",
    "def stockWeight(context, user_options=None):\n",
    "    return pd.Series(symbol_weights)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. 回测"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# -------------------------------------------------------------------------------\n",
    "# Main code 这个代码框不需要修改\n",
    "# -------------------------------------------------------------------------------\n",
    "\n",
    "def test_save_dataview():\n",
    "    ds = RemoteDataService()\n",
    "    ds.init_from_config(data_config)\n",
    "    dv = DataView()\n",
    "\n",
    "    props = {'start_date': start_date, 'end_date': end_date,\n",
    "             'fields': 'sw1',\n",
    "             'symbol': my_symbols,\n",
    "             'freq': 1}\n",
    "\n",
    "    dv.init_from_config(props, ds)\n",
    "    dv.prepare_data()\n",
    "\n",
    "    # set the benchmark\n",
    "    res, _ = ds.daily(benchmark, start_date=dv.start_date, end_date=dv.end_date)\n",
    "    dv._data_benchmark = res.set_index('trade_date').loc[:, ['close']]\n",
    "\n",
    "    dv.save_dataview(folder_path=dataview_dir_path)\n",
    "\n",
    "\n",
    "def test_alpha_strategy_dataview():\n",
    "    dv = DataView()\n",
    "\n",
    "    dv.load_dataview(folder_path=dataview_dir_path)\n",
    "\n",
    "    props = {\n",
    "        \"symbol\": dv.symbol,\n",
    "        \"universe\": ','.join(dv.symbol),\n",
    "\n",
    "        \"start_date\": dv.start_date,\n",
    "        \"end_date\": dv.end_date,\n",
    "\n",
    "        \"period\": \"week\",\n",
    "        \"days_delay\": 0,\n",
    "\n",
    "        \"init_balance\": 1e7,\n",
    "        \"position_ratio\": 1.0,\n",
    "        \"commission_rate\": 2E-4  # 手续费万2\n",
    "    }\n",
    "    props.update(data_config)\n",
    "    props.update(trade_config)\n",
    "\n",
    "    trade_api = AlphaTradeApi()\n",
    "\n",
    "    signal_model = model.FactorSignalModel()\n",
    "    signal_model.add_signal('stockWeight', stockWeight)\n",
    "\n",
    "    strategy = AlphaStrategy(signal_model=signal_model, pc_method='factor_value_weight')\n",
    "    pm = PortfolioManager()\n",
    "\n",
    "    bt = AlphaBacktestInstance()\n",
    "    \n",
    "    context = model.Context(dataview=dv, instance=bt, strategy=strategy, trade_api=trade_api, pm=pm)\n",
    "    \n",
    "    signal_model.register_context(context)\n",
    "\n",
    "    bt.init_from_config(props)\n",
    "\n",
    "    bt.run_alpha()\n",
    "\n",
    "    bt.save_results(folder_path=backtest_result_dir_path)\n",
    "    \n",
    "\n",
    "def test_backtest_analyze():\n",
    "    ta = ana.AlphaAnalyzer()\n",
    "    dv = DataView()\n",
    "    dv.load_dataview(folder_path=dataview_dir_path)\n",
    "\n",
    "    ta.initialize(dataview=dv, file_folder=backtest_result_dir_path)\n",
    "\n",
    "    ta.do_analyze(result_dir=backtest_result_dir_path, selected_sec=ta.universe,\n",
    "                  brinson_group=None)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Begin: DataApi login 18612562791@tcp://data.tushare.org:8910\n",
      "    login success \n",
      "\n",
      "Initialize config success.\n",
      "Query data...\n",
      "Query data - query...\n",
      "NOTE: price adjust method is [post adjust]\n",
      "Query data - daily fields prepared.\n",
      "Query instrument info...\n",
      "Query adj_factor...\n",
      "Query groups (industry)...\n",
      "Data has been successfully prepared.\n",
      "\n",
      "Store data...\n",
      "Dataview has been successfully saved to:\n",
      "C:\\Users\\jfang\\ipython\\demoStrategy\\dataview\n",
      "\n",
      "You can load it with load_dataview('C:\\Users\\jfang\\ipython\\demoStrategy\\dataview')\n",
      "Dataview loaded successfully.\n",
      "AlphaStrategy Initialized.\n",
      "\n",
      "=======new day 20170203\n",
      "Before 20170203 re-balance: available cash all (exclude suspensions) = 1.0000e+07\n",
      "\n",
      "=======new day 20170206\n",
      "Before 20170206 re-balance: available cash all (exclude suspensions) = 9.9970e+06\n",
      "\n",
      "=======new day 20170213\n",
      "Before 20170213 re-balance: available cash all (exclude suspensions) = 1.0272e+07\n",
      "\n",
      "=======new day 20170220\n",
      "Before 20170220 re-balance: available cash all (exclude suspensions) = 1.0588e+07\n",
      "\n",
      "=======new day 20170227\n",
      "Before 20170227 re-balance: available cash all (exclude suspensions) = 1.0392e+07\n",
      "\n",
      "=======new day 20170306\n",
      "Before 20170306 re-balance: available cash all (exclude suspensions) = 1.0421e+07\n",
      "\n",
      "=======new day 20170313\n",
      "Before 20170313 re-balance: available cash all (exclude suspensions) = 1.0586e+07\n",
      "\n",
      "=======new day 20170320\n",
      "Before 20170320 re-balance: available cash all (exclude suspensions) = 1.0679e+07\n",
      "\n",
      "=======new day 20170327\n",
      "Before 20170327 re-balance: available cash all (exclude suspensions) = 1.0875e+07\n",
      "\n",
      "=======new day 20170405\n",
      "Before 20170405 re-balance: available cash all (exclude suspensions) = 1.1042e+07\n",
      "\n",
      "=======new day 20170410\n",
      "Before 20170410 re-balance: available cash all (exclude suspensions) = 1.0972e+07\n",
      "\n",
      "=======new day 20170417\n",
      "Before 20170417 re-balance: available cash all (exclude suspensions) = 1.1001e+07\n",
      "\n",
      "=======new day 20170424\n",
      "Before 20170424 re-balance: available cash all (exclude suspensions) = 1.1102e+07\n",
      "\n",
      "=======new day 20170502\n",
      "Before 20170502 re-balance: available cash all (exclude suspensions) = 1.1384e+07\n",
      "\n",
      "=======new day 20170508\n",
      "Before 20170508 re-balance: available cash all (exclude suspensions) = 1.1185e+07\n",
      "\n",
      "=======new day 20170515\n",
      "Before 20170515 re-balance: available cash all (exclude suspensions) = 1.1912e+07\n",
      "\n",
      "=======new day 20170522\n",
      "Before 20170522 re-balance: available cash all (exclude suspensions) = 1.2314e+07\n",
      "\n",
      "=======new day 20170531\n",
      "Before 20170531 re-balance: available cash all (exclude suspensions) = 1.2731e+07\n",
      "\n",
      "=======new day 20170605\n",
      "Before 20170605 re-balance: available cash all (exclude suspensions) = 1.2575e+07\n",
      "\n",
      "=======new day 20170612\n",
      "Before 20170612 re-balance: available cash all (exclude suspensions) = 1.3607e+07\n",
      "\n",
      "=======new day 20170619\n",
      "Before 20170619 re-balance: available cash all (exclude suspensions) = 1.3395e+07\n",
      "\n",
      "=======new day 20170626\n",
      "Before 20170626 re-balance: available cash all (exclude suspensions) = 1.4174e+07\n",
      "\n",
      "=======new day 20170703\n",
      "Before 20170703 re-balance: available cash all (exclude suspensions) = 1.4002e+07\n",
      "\n",
      "=======new day 20170710\n",
      "Before 20170710 re-balance: available cash all (exclude suspensions) = 1.4163e+07\n",
      "\n",
      "=======new day 20170717\n",
      "Before 20170717 re-balance: available cash all (exclude suspensions) = 1.4825e+07\n",
      "\n",
      "=======new day 20170724\n",
      "Before 20170724 re-balance: available cash all (exclude suspensions) = 1.5073e+07\n",
      "\n",
      "=======new day 20170731\n",
      "Before 20170731 re-balance: available cash all (exclude suspensions) = 1.4850e+07\n",
      "\n",
      "=======new day 20170807\n",
      "Before 20170807 re-balance: available cash all (exclude suspensions) = 1.4856e+07\n",
      "\n",
      "=======new day 20170814\n",
      "Before 20170814 re-balance: available cash all (exclude suspensions) = 1.4737e+07\n",
      "\n",
      "=======new day 20170821\n",
      "Before 20170821 re-balance: available cash all (exclude suspensions) = 1.4929e+07\n",
      "\n",
      "=======new day 20170828\n",
      "Before 20170828 re-balance: available cash all (exclude suspensions) = 1.5544e+07\n",
      "\n",
      "=======new day 20170904\n",
      "Before 20170904 re-balance: available cash all (exclude suspensions) = 1.5298e+07\n",
      "\n",
      "=======new day 20170911\n",
      "Before 20170911 re-balance: available cash all (exclude suspensions) = 1.4900e+07\n",
      "\n",
      "=======new day 20170918\n",
      "Before 20170918 re-balance: available cash all (exclude suspensions) = 1.5037e+07\n",
      "\n",
      "=======new day 20170925\n",
      "Before 20170925 re-balance: available cash all (exclude suspensions) = 1.5265e+07\n",
      "Backtest done. 202 days, 1.34e+02 trades in total.\n",
      "Backtest results has been successfully saved to:\n",
      "C:\\Users\\jfang\\ipython\\demoStrategy\n",
      "Dataview loaded successfully.\n",
      "process trades...\n",
      "get daily stats...\n",
      "calc strategy return...\n",
      "Plot single securities PnL\n",
      "Plot strategy PnL...\n",
      "generate report...\n",
      "HTML report: C:\\Users\\jfang\\ipython\\demoStrategy\\report.html\n"
     ]
    }
   ],
   "source": [
    "# 运行这里跑回测\n",
    "test_save_dataview()\n",
    "test_alpha_strategy_dataview()\n",
    "test_backtest_analyze()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "回测显示运行完成后，报告可从上面对话框最后一行的地址中找到 `HTML report: ...\\demoStrategy\\report.html`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. 仿真交易"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from jaqs.trade.tradeapi import TradeApi"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Exception No module named 'jrpc'\n",
      "TradeApi: _on_connected\n"
     ]
    }
   ],
   "source": [
    "tapi = TradeApi(trade_config['remote.trade.address'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def on_orderstatus(order):\n",
    "    print(\"on_orderstatus:\") #, order\n",
    "    for key in order:    print(\"%20s : %s\" % (key, str(order[key])))\n",
    "    print(\"\")\n",
    "\n",
    "\n",
    "# 成交回报推送\n",
    "def on_trade(trade):\n",
    "    print(\"on_trade:\")\n",
    "    for key in trade:    print(\"%20s : %s\" % (key, str(trade[key])))\n",
    "    print(\"\")\n",
    "\n",
    "# 委托任务执行状态推送\n",
    "# 通常可以忽略该回调函数\n",
    "def on_taskstatus(task):\n",
    "    print(\"on_taskstatus:\")\n",
    "    for key in task:    print(\"%20s : %s\" % (key, str(task[key])))\n",
    "    print(\"\")\n",
    "\n",
    "tapi.set_ordstatus_callback(on_orderstatus)\n",
    "tapi.set_trade_callback(on_trade)\n",
    "tapi.set_task_callback(on_taskstatus)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "user_info, msg = tapi.login(trade_config['remote.trade.username'], trade_config['remote.trade.password'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'username': '18612562791', 'name': 'jfang', 'strategies': [1008, 1009, 1010], 'broker_strategies': []}\n",
      "   close_pnl  deposit_balance  enable_balance  float_pnl  frozen_balance  \\\n",
      "0        0.0              0.0     100000000.0   -55544.0             0.0   \n",
      "1        0.0              0.0     100000000.0   -55544.0             0.0   \n",
      "\n",
      "   holding_pnl    id  init_balance  margin  trading_pnl type  \n",
      "0      52580.0  1008   100000000.0     0.0          0.0   SA  \n",
      "1      52580.0  1008   100000000.0     0.0          0.0   BA  \n",
      "Balance we have: 100000000.0\n"
     ]
    }
   ],
   "source": [
    "print(user_info)\n",
    "tapi.use_strategy(StrategyNo)  #改成用户自己的 strategy号\n",
    "\n",
    "res, msg = tapi.query_account()\n",
    "print(res)\n",
    "\n",
    "money = res.loc[0, 'enable_balance']\n",
    "print(\"Balance we have: {}\".format(money))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'action': 'Buy', 'price': 637.7, 'security': '600519.SH', 'size': 400.0},\n",
       " {'action': 'Buy', 'price': 28.72, 'security': '600036.SH', 'size': 10400.0},\n",
       " {'action': 'Buy', 'price': 63.29, 'security': '601318.SH', 'size': 4700.0},\n",
       " {'action': 'Buy', 'price': 41.96, 'security': '000651.SZ', 'size': 7100.0}]"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dic_price      = {'600519.SH': 637.70,\n",
    "                  '600036.SH': 28.72,\n",
    "                  '601318.SH': 63.29,\n",
    "                  '000651.SZ': 41.96}\n",
    "\n",
    "# 每只股票等金额投资，各买入30万元\n",
    "dic_shares = {k: 100 * np.floor(money * 0.012 * symbol_weights[k] / dic_price[k]/100) for k, _ in symbol_weights.items()}\n",
    "dic_shares\n",
    "\n",
    "orders = []\n",
    "for symbol in symbol_weights.keys():\n",
    "    o = {'security': symbol, 'price': dic_price[symbol], 'size': dic_shares[symbol], 'action': 'Buy'}\n",
    "    orders.append(o)\n",
    "orders"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10081211000001\n",
      "0,scheduled in 142837215 ms\n",
      "on_orderstatus:\n",
      "               sa_id : 1008\n",
      "               ba_id : 100800\n",
      "          entrust_no : 10081211000001\n",
      "            security : 600519.SH\n",
      "      entrust_action : Buy\n",
      "       entrust_price : 637.7\n",
      "        entrust_size : 400\n",
      "        entrust_date : 20171209\n",
      "        entrust_time : 174922\n",
      "             ord_seq : 0\n",
      "            batch_no : 0\n",
      "        order_status : New\n",
      "         is_finished : False\n",
      "          fill_price : 0.0\n",
      "           fill_size : 0\n",
      "          commission : 0.0\n",
      "             task_id : 10081211000001\n",
      "                algo : \n",
      "\n",
      "on_orderstatus:\n",
      "               sa_id : 1008\n",
      "               ba_id : 100800\n",
      "          entrust_no : 10081211000002\n",
      "            security : 600036.SH\n",
      "      entrust_action : Buy\n",
      "       entrust_price : 28.72\n",
      "        entrust_size : 10400\n",
      "        entrust_date : 20171209\n",
      "        entrust_time : 174922\n",
      "             ord_seq : 1\n",
      "            batch_no : 0\n",
      "        order_status : New\n",
      "         is_finished : False\n",
      "          fill_price : 0.0\n",
      "           fill_size : 0\n",
      "          commission : 0.0\n",
      "             task_id : 10081211000001\n",
      "                algo : \n",
      "\n",
      "on_orderstatus:\n",
      "               sa_id : 1008\n",
      "               ba_id : 100800\n",
      "          entrust_no : 10081211000003\n",
      "            security : 601318.SH\n",
      "      entrust_action : Buy\n",
      "       entrust_price : 63.29\n",
      "        entrust_size : 4700\n",
      "        entrust_date : 20171209\n",
      "        entrust_time : 174922\n",
      "             ord_seq : 2\n",
      "            batch_no : 0\n",
      "        order_status : New\n",
      "         is_finished : False\n",
      "          fill_price : 0.0\n",
      "           fill_size : 0\n",
      "          commission : 0.0\n",
      "             task_id : 10081211000001\n",
      "                algo : \n",
      "\n",
      "on_orderstatus:\n",
      "               sa_id : 1008\n",
      "               ba_id : 100800\n",
      "          entrust_no : 10081211000004\n",
      "            security : 000651.SZ\n",
      "      entrust_action : Buy\n",
      "       entrust_price : 41.96\n",
      "        entrust_size : 7100\n",
      "        entrust_date : 20171209\n",
      "        entrust_time : 174922\n",
      "             ord_seq : 3\n",
      "            batch_no : 0\n",
      "        order_status : New\n",
      "         is_finished : False\n",
      "          fill_price : 0.0\n",
      "           fill_size : 0\n",
      "          commission : 0.0\n",
      "             task_id : 10081211000001\n",
      "                algo : \n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 买入股票\n",
    "task_id, msg = tapi.place_batch_order(orders)\n",
    "print(task_id)\n",
    "print(msg)    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "0,IF1712.CFE not in UNIVERSE\n"
     ]
    }
   ],
   "source": [
    "# 做空一手沪深300股指期货做对冲\n",
    "# task_id, msg = tapi.place_order(\"IF1712.CFE\", \"Short\", 4003.6, 1)\n",
    "# print(task_id)\n",
    "# print(msg)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
